﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Workflow.Runtime.Hosting;
using Evaluant.Uss.ObjectContext;
using System.Workflow.ComponentModel;
using System.Workflow.Runtime;

namespace Evaluant.Uss.Workflow
{
    public class EussWorkflowPersistenceService : WorkflowPersistenceService
    {
        static ObjectService os;
        static Guid Id = Guid.NewGuid();
        Evaluant.Uss.ObjectContext.ObjectContext oc;
        bool unloadOnIdle;
        TimeSpan instanceOwnershipDuration;
        TimeSpan loadInterval;
        Guid serviceId;
        object timerLock;

        protected bool serializeTerminatedWorkflows;
        public bool SerializeTerminatedWorkflows
        {
            get { return serializeTerminatedWorkflows; }
            set { serializeTerminatedWorkflows = value; }
        }


        public void InitializeRepository()
        {
            oc = os.CreateObjectContext();
            oc.InitializeRepository();
        }

        public EussWorkflowPersistenceService(ObjectService os, bool unloadOnIdle)
        {
            this.unloadOnIdle = unloadOnIdle;
            EussWorkflowPersistenceService.os = os;
        }

        public EussWorkflowPersistenceService(bool unloadOnIdle, TimeSpan instanceOwnershipDuration, TimeSpan loadInterval)
        {
            this.unloadOnIdle = unloadOnIdle;
            this.instanceOwnershipDuration = instanceOwnershipDuration;
            this.loadInterval = loadInterval;
            this.serviceId = Guid.NewGuid();
            this.timerLock = new object();
        }

        protected override Activity LoadCompletedContextActivity(Guid scopeId, Activity outerActivity)
        {
            oc = os.CreateObjectContext();
            Activity contextActivity = null;
            try
            {
                byte[] instanceState = oc.LoadWithId<CompletedScope>(scopeId.ToString()).State;

                contextActivity = RestoreFromDefaultSerializedForm(instanceState, outerActivity);
            }
            catch (Exception e)
            {
                base.RaiseServicesExceptionNotHandledEvent(e, Guid.Empty);
            }

            return contextActivity;

        }

        protected override Activity LoadWorkflowInstanceState(Guid instanceId)
        {
            try
            {
                oc = os.CreateObjectContext();
                return RestoreFromSerialization(GetInstanceState(instanceId).State, null);
            }
            catch
            {
                throw;
                // Retrouver nom de l'exception à gérer en cas d'incompatibilité de type
            }
        }

        protected override void SaveCompletedContextActivity(System.Workflow.ComponentModel.Activity activity)
        {
            if (serializeTerminatedWorkflows)
            {
                oc = os.CreateObjectContext();

                try
                {
                    CompletedScope workItem = new CompletedScope();
                    workItem.State = GetDefaultSerializedForm(activity);
                    workItem.UidInstanceId = WorkflowEnvironment.WorkflowInstanceId.ToString();
                    workItem.Id = activity.GetValue(Activity.ActivityContextGuidProperty).ToString();

                    oc.BeginTransaction();
                    oc.Serialize(workItem);
                    if (workItem.UidInstanceId == workItem.Id)
                        oc.Delete(GetInstanceState(WorkflowEnvironment.WorkflowInstanceId));
                    oc.CommitTransaction();
                }
                catch (Exception e)
                {
                    base.RaiseServicesExceptionNotHandledEvent(e, WorkflowEnvironment.WorkflowInstanceId);
                }
            }
        }

        InstanceState GetInstanceState(Guid guid)
        {
            Query q = new Query(typeof(InstanceState));
            //q.InferredAttributes.Add("UidInstanceId");
            q.Constraint = String.Format("[id('{0}')]", guid);
            q.FirstResult = 1;
            q.MaxResults = 1;
            IList<InstanceState> instances = oc.Load<InstanceState>(q);
            if (instances.Count > 0)
                return instances[0];
            InstanceState result = new InstanceState();
            result.Id = guid.ToString();
            result.OwnerId = EussWorkflowPersistenceService.Id;
            return result;
        }

        protected override void SaveWorkflowInstanceState(System.Workflow.ComponentModel.Activity rootActivity, bool unlock)
        {
            oc = os.CreateObjectContext();
            InstanceState instance = GetInstanceState(WorkflowEnvironment.WorkflowInstanceId);

            WorkflowStatus status = GetWorkflowStatus(rootActivity);
            if (status != WorkflowStatus.Completed || status != WorkflowStatus.Terminated)
                instance.State = GetSerialization(rootActivity);
            else
                instance.State = new byte[0];

            TimerEventSubscription timerEventSubscription =
                ((TimerEventSubscriptionCollection)rootActivity.GetValue(
                TimerEventSubscriptionCollection.TimerCollectionProperty)).Peek();

            if (timerEventSubscription == null)
                instance.NextTimer = null;
            else
                instance.NextTimer = timerEventSubscription.ExpiresAt;

            instance.Unlocked = (unlock) ? 1 : 0;
            if (status != WorkflowStatus.Terminated || (serializeTerminatedWorkflows && status == WorkflowStatus.Terminated))
            {
                oc.BeginTransaction();
                oc.Serialize(instance);
                oc.CommitTransaction();
            }
        }

        protected override bool UnloadOnIdle(System.Workflow.ComponentModel.Activity activity)
        {
            return unloadOnIdle;
        }

        protected override void UnlockWorkflowInstanceState(System.Workflow.ComponentModel.Activity rootActivity)
        {
            SaveWorkflowInstanceState(rootActivity, true);
        }

        protected virtual byte[] GetSerialization(Activity rootActivity)
        {
            return GetDefaultSerializedForm(rootActivity);
        }

        protected virtual Activity RestoreFromSerialization(byte[] activityBytes, Activity outerActivity)
        {
            return RestoreFromDefaultSerializedForm(activityBytes, outerActivity);
        }
    }/*
    {
        protected override WFTools.Services.IResourceProvider CreateResourceProvider()
        {
            return new EussResourceProvider();
        }

        protected override IResourceAccessor CreateAccessor(WFTools.Services.IResourceProvider resourceProvider)
        {
            return ((EussResourceProvider)resourceProvider).CreateResourceAccessor();
        }

        protected override IResourceAccessor CreateAccessor(WFTools.Services.IResourceProvider resourceProvider, System.Transactions.Transaction transaction)
        {
            return CreateAccessor(resourceProvider);
        }
    }*/
}
